
#include <rtdef.h>
#include <rtthread.h>
#include <rthw.h>

#include "PRINT/my_printf.h"

#include "LED/led.h"
#include "KEY/key.h"
#include "UART/uart.h"
#include "PLL/pll.h"
#include "PRINT/my_printf.h"
#include "VIC/vic_reg.h"
#include "INIT/init.h"
#include "EXTI/exti.h"
#include "TIMER/timer.h"
#include "SDIO/sdio.h"
#include "PUBLIC/test.h"
#include "PUBLIC/public.h"

#include "nnom.h"
#include "NNOM/image.h"
#include "NNOM/weights.h"


struct rt_thread *rt_led_thread;
struct rt_thread *rt_parse_thread;

rt_timer_t sft_timer1, sft_timer2;

extern rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];
extern u32 PendSV_Handler;
extern rt_uint32_t rt_thread_switch_interrupt_flag;
extern rt_uint32_t rt_interrupt_to_thread;

extern rt_tick_t rt_tick;

rt_sem_t cmd_sem;
extern char uart0_buff[100];

nnom_model_t *model;

struct my_msg{
    rt_base_t data;
    rt_sem_t sem;
};

#define RECV_MAIL        (1 << 3)
#define EVENT_FLAG5     (1 << 5)

void cmd_release(){
    if(rt_sem_release(cmd_sem) == RT_ERROR){
        rt_kprintf("cmd_sem release FAIL!\n");
    }
}

void cmd_parse_thread_entry(){

    uint32_t tick, time;
	uint32_t predic_label;
	float prob;
	int32_t index = 3;
    
    // for(int i = 0; i < 10; i++){
    //     print_img((int8_t *)&img[i][0]);
    // }

    while(1){
        rt_kprintf("RT-Thread >$");
        if(rt_sem_take(cmd_sem, RT_WAITING_FOREVER) == RT_EOK){
            // mnist
            if(uart0_buff[0] == 'm' && uart0_buff[4] == 't'){

                index = uart0_buff[6] - '0';

                printf("\nprediction start.. \n", ' ');
                tick = rt_tick_get();
                
                // copy data and do prediction
                rt_memcpy(nnom_input_data, (int8_t*)&img[index][0], 784);
                nnom_predic(model, &predic_label, &prob);
                time = rt_tick_get() - tick;
                
                //print original image to console
                print_img((int8_t*)&img[index][0]);
                
                printf("Time: %d tick\n", time);
                printf("Truth label: %d\n", label[index]);
                printf("Predicted label: %d\n", predic_label);
                printf("Probability: %d%%\n\n", (int)(prob*100));

                uart0_buff[0] = 0;
            }
        }
    }
}


const char codeLib[] = "@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\"^`'.   ";
void print_img(int8_t * buf)
{
    for(int y = 0; y < 28; y++) 
	{
        for (int x = 0; x < 28; x++) 
		{
            int index =  69 / 127.0 * (127 - buf[y*28+x]); 
			if(index > 69) index =69;
			if(index < 0) index = 0;
            printf("%c",codeLib[index]);
			printf("%c",codeLib[index]);
        }
        rt_kprintf("\n");
    }
}

void led_thread_entry(void *p_arg){
    
    while(1){
        led1_on();
        rt_thread_delay(50);

        led1_off();
        rt_thread_delay(50);

    }
}

int main(){
    
    /* 关中断 */
    rt_hw_interrupt_disable();

    // rt_tick = 0;
    // printf("tick %x %d \n", &rt_tick, rt_tick_get());

    vic_init(63, (u32)&PendSV_Handler); // 调度中断
    led_init();
    // key_init();
    
    /* 设置SysTick中断频率 */
    SysTick_Config();

    rt_system_signal_init();
    
    /* 系统定时器列表初始化 */
    rt_system_timer_init();
    
    /* 初始化系统调度器 */
    rt_system_scheduler_init();

    /* 初始化空闲线程 */    
    rt_thread_idle_init();

    /* 初始化软件定时器 */
    rt_system_timer_thread_init();

    for(int i = 0; i < 8; i++){
        rt_kprintf("\b\r");
    }

    rt_kprintf("                                                        \n");
    rt_kprintf("                    ██╗    ██╗███████╗██╗   ██╗██╗   ██╗\n");
    rt_kprintf("                    ██║    ██║██╔════╝╚██╗ ██╔╝██║   ██║\n");
    rt_kprintf("                    ██║ █╗ ██║███████╗ ╚████╔╝ ██║   ██║\n");
    rt_kprintf("                    ██║███╗██║╚════██║  ╚██╔╝  ██║   ██║\n");
    rt_kprintf("                    ╚███╔███╔╝███████║   ██║   ╚██████╔╝\n");
    rt_kprintf("                     ╚══╝╚══╝ ╚══════╝   ╚═╝    ╚═════╝ \n");
    rt_kprintf("                                                        \n");
    rt_kprintf("                         基于RT-Thread的手写数字识别      \n");

    cmd_sem = rt_sem_create("cmd_sem", 0, RT_IPC_FLAG_FIFO);
    if(cmd_sem == RT_NULL){
        rt_kprintf("cmd_sem create FAIL!\n");
    }

    // create and compile the model 
	model = nnom_model_create();
	// rt_kprintf("model: %x\n", model);
	// dummy run
	model_run(model);
    // rt_kprintf("model run\n", ' ');

    rt_led_thread = rt_thread_create("thread3", led_thread_entry, RT_NULL, 20480, 2, 10);
    rt_thread_startup(rt_led_thread);

    rt_parse_thread = rt_thread_create("cmd", cmd_parse_thread_entry, RT_NULL, 20480, 2, 10);
    rt_thread_startup(rt_parse_thread);
    
    rt_system_scheduler_start();
    
    return 0;
}


void SysTick_Handler(void)
{
    /* 进入中断 */
    rt_interrupt_enter();

    rt_tick_increase();

    TINT_CSTAT |= (1 << 5); // 清除中断标志

    /* 离开中断 */
    rt_interrupt_leave();
}
